import React from "react";

class GridItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      layout: {},
      lastLayout: new Map(),
      mouseDownX: 0,
      mouseDownY: 0,
      newW: 0,
      newH: 0,
      lastX: 0,
      lastY: 0,
      style: {
        position: "relative",
        zIndex: 1,
        opacity: 1,
      },
    };
    this.dom = null;
  }

  componentWillMount() {
    const {w, h} = this.props.layout;
    this.calWHtoPx(w, h);
    this.setState({
      layout: {...this.props.layout}
    })
  }

  componentDidMount() {
  }

  componentWillReceiveProps(nextProps) {
    const {w, h} = nextProps.layout;
    this.calWHtoPx(w, h);
    this.setState({
      layout: {...nextProps.layout}
    })
  }

  /** 计算容器的栅格每一个格子多宽 */
  calColWidth = () => {
    const {containerWidth, col, containerPadding, margin} = this.props;
    return (containerWidth - containerPadding[1] * 2 - margin[1] * col) / col
  };

  /**给予一个grid的位置，算出元素具体的在容器中的坐标*/
  calGridItemPosition = (GridX, GridY) => {
    const {margin, rowHeight} = this.props;
    let originX = GridX * this.calColWidth() + GridX * margin[1];
    let originY = GridY * rowHeight + GridY * margin[0];
    return {
      originX,
      originY
    };
  };

  /**宽和高计算成为px */
  calWHtoPx = (w, h) => {
    const {margin, rowHeight} = this.props;
    const wPx = w * this.calColWidth() + (w - 1) * margin[1];
    const hPx = h * rowHeight + (h - 1) * margin[0];
    this.setState({
      wPx: wPx,
      hPx: hPx,
      lastX: wPx,
      lastY: hPx
    });
  };

  onDrag = (e) => {
    const {mouseDownX, mouseDownY, originX, originY} = this.state;
    const {draggingStyle} = this.props;
    const {key} = this.state.layout;
    let x = e.pageX || e.x;
    let y = e.pageY || e.y;
    this.setState({
      style: {
        ...draggingStyle,
        zIndex: 3,
        opacity: 0.8,
        position: "absolute",
        top: y - mouseDownY + originY,
        left: x - mouseDownX + originX
      }
    }, () => {
      this.props.onDrag(x - mouseDownX + originX, y - mouseDownY + originY, this.dom, key)
    });
  };

  onDragStart = (e) => {
    e.persist();
    this.dom = e.target.parentNode;
    const {wPx, hPx} = this.state;
    if (window.addEventListener) {
      document.addEventListener('mousemove', this.onDrag);
      document.addEventListener('mouseup', this.onDragEnd);
    } else {
      document.attachEvent('onmousemove', this.onDrag);
      document.attachEvent('onmouseup', this.onDragEnd);
    }
    this.setState({
      mouseDownX: e.pageX || e.x,
      mouseDownY: e.pageY || e.y,
      originX: e.target.parentNode.offsetLeft,
      originY: e.target.parentNode.offsetTop,
      style: {
        zIndex: 3,
        opacity: 0.8,
        position: "absolute",
        top: e.target.parentNode.offsetTop,
        left: e.target.parentNode.offsetLeft,
        transition: "none"
      }
    }, () => {
      this.props.onDragStart(this.props.layout.order, wPx, hPx);
    })
  };

  onDragEnd = (e) => {
    if (window.addEventListener) {
      document.removeEventListener('mousemove', this.onDrag);
      document.removeEventListener('mouseup', this.onDragEnd);
    } else {
      document.detachEvent('onmousemove', this.onDrag);
      document.detachEvent('onmouseup', this.onDragEnd);
    }
    this.setState({
      style: {
        zIndex: 1,
        opacity: 1,
        position: "relative",
        top: 0,
        left: 0,
        transition: "auto"
      }
    }, () => {
      this.props.onDragEnd(this.props.layout.key);
    });
  };

  onResizeX = e => {
    const {mouseDownX, lastX, lastY} = this.state;
    let x = e.pageX || e.x;
    this.setState({
      wPx: Math.max(x - mouseDownX + lastX, this.calColWidth()),
    }, () => {
      this.props.onResizeX(x - mouseDownX, this.calColWidth(), this.state.layout, lastY)
    })
  };

  onResizeY = e => {
    const {mouseDownY, lastX, lastY} = this.state;
    const {rowHeight, draggableHeight} = this.props;
    let y = e.pageY || e.y;
    this.setState({
      hPx: Math.max(y - mouseDownY + lastY, rowHeight, draggableHeight)
    }, () => {
      this.props.onResizeY(y - mouseDownY, this.calColWidth(), this.state.layout, lastX)
    })
  };

  onResizeF = e => {
    const {mouseDownX, lastX, lastY} = this.state;
    const percent = lastY / lastX;
    let x = e.pageX || e.x;
    this.setState({
      wPx: Math.max(x - mouseDownX + lastX, this.calColWidth()),
      hPx: Math.max(x - mouseDownX + lastX, this.calColWidth()) * percent
    }, () => {
      this.props.onResizeF(x - mouseDownX, this.calColWidth(), this.state.layout, percent)
    })
  };

  onResizeStart = (type, e) => {
    e.persist();
    e.target.style.backgroundColor = "rgba(24, 144, 255, 0.6)";
    this.dom = e.target;
    const {key} = this.state.layout;
    if (window.addEventListener) {
      type === "X" && document.addEventListener('mousemove', this.onResizeX);
      type === "Y" && document.addEventListener('mousemove', this.onResizeY);
      type === "F" && document.addEventListener('mousemove', this.onResizeF);
      document.addEventListener('mouseup', this.onResizeEnd);
    } else {
      type === "X" && document.attachEvent('onmousemove', this.onResizeX);
      type === "Y" && document.attachEvent('onmousemove', this.onResizeY);
      type === "F" && document.attachEvent('onmousemove', this.onResizeF);
      document.attachEvent('onmouseup', this.onResizeEnd);
    }
    this.setState({
      mouseDownX: e.pageX || e.x,
      mouseDownY: e.pageY || e.y,
      style: {
        zIndex: 3,
        opacity: 0.8,
        position: "absolute",
        top: e.target.parentNode.offsetTop,
        left: e.target.parentNode.offsetLeft
      }
    }, () => {
      this.props.onResizeStart(key, this.calColWidth());
    })
  };

  onResizeEnd = () => {
    this.dom.style.backgroundColor = "transparent";
    if (window.addEventListener) {
      document.removeEventListener('mousemove', this.onResizeX);
      document.removeEventListener('mousemove', this.onResizeY);
      document.removeEventListener('mousemove', this.onResizeF);
      document.removeEventListener('mouseup', this.onResizeEnd);
    } else {
      document.detachEvent('onmousemove', this.onResizeX);
      document.detachEvent('onmousemove', this.onResizeY);
      document.detachEvent('onmousemove', this.onResizeF);
      document.detachEvent('onmouseup', this.onResizeEnd);
    }
    this.setState({
      style: {
        zIndex: 1,
        opacity: 1,
        position: "relative",
        top: 0,
        left: 0
      }
    }, () => {
      this.props.onResizeEnd(this.state.layout.key);
    });
  };

  render() {
    const { wPx, hPx, style } = this.state;
    const { key, order, firm, minW, minH } = this.state.layout;
    const { margin, isOperating } = this.props;
    const flexOrder = {
      WebkitBoxOrdinalGroup: order,
      MozBoxOrdinalGroup: order,
      MsFlexOrder: order,
      WebkitOrder: order,
      order: order
    };
    const provided = {
      key: key,
      className: "layout-item",
      style: {
        ...style,
        ...flexOrder,
        marginBottom: margin[0],
        marginRight: margin[1],
        width: wPx,
        height: hPx
      }
    };
    return (
      <div className="layout-item" key={key} style={provided.style}>
        {isOperating && <div className="toggle-area" onMouseDown={this.onDragStart} />}
        {isOperating && !firm && <div className="resizeR-area" onMouseDown={this.onResizeStart.bind(this, "X")}></div>}
        {isOperating && !firm && <div className="resizeB-area" onMouseDown={this.onResizeStart.bind(this, "Y")}></div>}
        {this.props.children({style: {minWidth: minW, minHeight: minH, width: wPx, height: hPx}})}
      </div>
    )
  }
}

GridItem.propTypes = {
  containerWidth: React.PropTypes.number.isRequired, // 容器宽度
  col: React.PropTypes.number.isRequired, //栅格，于是容器内元素的最小宽度就等于 width/col
  rowHeight: React.PropTypes.number.isRequired, //行高，于是容器内元素的最小高度就等于 rowHeight
  margin: React.PropTypes.array.isRequired, //元素间隙，每个元素的margin [marginBottom, marginRight]
  containerPadding: React.PropTypes.array, //容器的padding [上下padding，左右padding]
  layout: React.PropTypes.object.isRequired,
  isOperating: React.PropTypes.bool,
  onDrag: React.PropTypes.func,
  onDragStart: React.PropTypes.func,
  onDragEnd: React.PropTypes.func,
  onResizeX: React.PropTypes.func,
  onResizeY: React.PropTypes.func,
  onResizeF: React.PropTypes.func,
  onResizeStart: React.PropTypes.func,
  onResizeEnd: React.PropTypes.func,
  toggleBox: React.PropTypes.func,
  draggableHeight: React.PropTypes.number,
  draggingStyle: React.PropTypes.obj,
};
GridItem.defaultProps = {
  draggingStyle: {},
  // containerPadding: [10,10]
};
export default GridItem;
